🌱
Sealed Class
March 31, 2023
Sealed Class
코틀린 sealed class 공식문서를 참고했습니다.
목적
클래스의 상속을 더 제어하기 위해 사용한다.
코틀린은 예약어를 통해 컴파일 과정에서 편의성을 제공하는 방식을 좋아하는 듯 하다.
interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
fun eval(e: Expr): Int =
when (e) {
is Num -> e.value
is Sum -> eval(e.right) + eval(e.left)
else ->
throw IllegalArgumentException("Unknown expression")
}
이 구조에서, when 식의 else를 주목하자.
Expr
를 구현한 새로운 Class가 생긴다면, else문은 논리 오류가 될 수 있다.
즉, 하위 클래스가 추가 됐을 때 컴파일러가 when이 모든 분기를 처리하는지 알 수 없다.
또 새로운 클래스 처리를 잊어버려도 알 수 없다.
이 문제에 대한 해법이 sealed class
이다.
sealed class Expr {
class Num(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
}
fun eval(e: Expr): Int =
when (e) {
is Num -> e.value
is Sum -> eval(e.right) + eval(e.left)
}
sealed class
를 상속하는 하위 클래스는 무조건 중첩 클래스로 구현되어야 한다.
when식이 모든 하위 타입을 검사하는지 컴파일러는 알 수 있고, 새로운 클래스가 분기처리 되지 않으면 컴파일 오류가 난다.
sealed class
는 그 자체로 abstract 하고, 인스턴스화 할 수 없다.
코틀린 1.5부터는 너무 많은 제약을 해소했다.
하위 클래스는 중첩 클래스가 아닌 sealed class
가 정의된 패키지 안에서 구현할 수 있고,
sealed interface
도 추가됐다.
기존에 sealed interface
가 없던 이유는 자바에서 해당 인터페이스를 확장하지 못하게 할 방법이 없기 때문이라고 했는데,
이 문제가 어떻게 해결된 것인지 모르겠다.